/**
 * JAVACC DEMO 1.0
 * @copy right dwusoft company All rights reserved. 
 * @Package com.dwusoft.buss.common  
 */
package com.dwusoft.ius;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.apache.api.vo.ParamsVo;
import com.apache.cache.util.Validator;
import com.apache.database.constant.SpringContextLoader;
import com.apache.database.constant.SystemTools;
import com.apache.database.db.IDao;
import com.apache.database.model.MethodParam;
import com.apache.exception.BusinessException;
import com.apache.tools.DateUtils;
import com.apache.tools.NumberUtils;
import com.dwusoft.ius.function.FelFunction;
import com.greenpineyu.fel.FelEngine;
import com.greenpineyu.fel.FelEngineImpl;
import com.greenpineyu.fel.context.FelContext;

/**
 * description:  表达式计算类
 * @author Administrator 创建时间：2016-12-8  
 * @Copyright(c)2014:东吴（北京）软件技术有限公司
 */
public class FelToolsUtil {
	private Logger log = Logger.getLogger(getClass());

	private static FelToolsUtil instance;
	private IDao trpCateDao;

	private FelToolsUtil() {
		trpCateDao = (IDao) SpringContextLoader.getBean("trpCateDao");
	}

	public static FelToolsUtil getInstance() {
		if (null == instance) {
			instance = new FelToolsUtil();
		}
		return instance;
	}

	public void evl(ParamsVo vo) {
		String cateNo = String.valueOf(vo.getParams("cateNo"));//品种类型
		String saleId = String.valueOf(vo.getParams("saleId"));//品种类型
		String proId = String.valueOf(vo.getParams("proId"));//品种类型
		String constantType = String.valueOf(vo.getParams("constantType"));//流程类型 主流程/受让方流程等
		String constantStatus = String.valueOf(vo.getParams("constantStatus"));//当前状态
		MethodParam params = new MethodParam("ByObjInfo", "", "", "com.dwusoft.net.trans.TransPublic");

		StringBuffer execSql = new StringBuffer("select * from trs_rules_pro where constant_type='" + constantType
				+ "' and constant_status='" + constantStatus + "' ");
		if (Validator.isNotNull(saleId)) {
			execSql.append("and sale_id='" + saleId + "' ");
		}
		if (Validator.isNotNull(proId)) {
			execSql.append("and prod_id='" + proId + "' ");
		}
		execSql.append("order by order_no+0 asc");
		params.setParams("dyncSql", execSql.toString());
		List list = trpCateDao.select(params);
		if (Validator.isEmpty(list))
			return;

		Map<String, Object> param = vo.getParams();
		for (int i = 0; i < list.size(); i++) {
			Map map = (Map) list.get(i);
			// numCalculate:数值公式计算类;numValidate:数值校验类;dateCalculate:日期公式计算类;dateValidate:日期校验类;custom:自定义方法类;
			String dealType = String.valueOf(map.get("dealType"));
			String formulaCal = String.valueOf(map.get("formulaCal"));
			String rulesNo = String.valueOf(map.get("rulesNo"));
			String formulaName = String.valueOf(map.get("formulaName"));
			String paramNo = String.valueOf(map.get("paramNo"));
			param.put("rulesNo", rulesNo);
			param.put("paramNo", paramNo);
			param.put("formulaName", formulaName);
			if ("numCalculate".equals(dealType)) {
				//trpPro.proAmount=trpPro.price*trpPub.itemNum+trpPro.priceTotal
				String str[] = formulaCal.split("=");
				vo.setParams(str[0], numCalculateForFel(formulaCal, param));
			} else if ("numValidate".equals(dealType)) {
				numValidate(formulaCal, param);
			} else if ("dateValidate".equals(dealType)) {
				dateValidate(formulaCal, param);
			} else if ("dateCalculate".equals(dealType)) {
				String str[] = formulaCal.split("=");
				Object rs = dateCalculate(formulaCal, param);
				String keys[] = str[0].split(":");
				if (keys.length > 1) {
					vo.setParams(keys[1], rs);
				} else {
					vo.setParams(str[0], rs);
				}
			} else if ("custom".equals(dealType)) {
				try {
					Class cls = Class.forName(formulaCal);
					Method m = cls.getDeclaredMethod("run", new Class[] { ParamsVo.class });
					m.invoke(cls.newInstance(), vo);
				} catch (Exception e) {
					e.printStackTrace();
					throw new BusinessException(e.getCause().getMessage());
				}
			}

		}
	}

	public void calculate(ParamsVo vo) {

	}

	public boolean compare(ParamsVo vo) {
		return false;
	}

	/**
	 * description:  数值公式计算类
	 */
	private Object numCalculateForFel(String formulaCal, Map<String, Object> param) {
		FelEngine fel = new FelEngineImpl();
		formulaCal = formulaCal.replace("==", "###");
		formulaCal = formulaCal.replace("[[", "'").replace("]]", "'");

		String str[] = formulaCal.split("=");
		FelContext ctx = fel.getContext();
		String eval = str[1];
		for (String key : param.keySet()) {
			if (str[1].indexOf(key) != -1) {
				String val = String.valueOf(param.get(key));
				if (isNumeric(val)) {
					ctx.set(key.replace(".", "_"), Double.valueOf(val));
				} else {
					ctx.set(key.replace(".", "_"), val);
				}

				eval = eval.replace(key, key.replace(".", "_"));
				//str[1] = str[1].replace(key, String.valueOf(param.get(key)));
			}
		}
		eval = eval.replace("###", "==");
		Object result = fel.eval(eval);
		String res = NumberUtils.format(Double.valueOf(String.valueOf(result)), 2, false);
		log.info("numCalculateForFel-规则[" + param.get("formulaName") + "][" + eval + "]->处理结果：" + res);
		return res;
	}

	/**
	 * description:  数值公式校验类
	 */
	private boolean numValidate(String formulaCal, Map<String, Object> param) {
		FelEngine fel = new FelEngineImpl();
		FelContext ctx = fel.getContext();
		for (String key : param.keySet()) {
			if (formulaCal.indexOf(key) != -1) {
				ctx.set(key.replace(".", "_"), Double.valueOf(String.valueOf(param.get(key))));
				formulaCal = formulaCal.replace(key, key.replace(".", "_"));
				//formulaCal = formulaCal.replace(key, String.valueOf(param.get(key)));
			}
		}

		if (formulaCal.indexOf(">") == -1 && formulaCal.indexOf("<") == -1 && formulaCal.indexOf("==") == -1) {
			String compareStr[] = formulaCal.split("=");
			Object result = fel.eval(compareStr[1].replace(".", "_"));
			//如果不是整数，则默认保留小数点后两位。
			if (String.valueOf(result).contains(".")) {
				result = String.format("%.2f", result);
			}
			Object paramResult = param.get(compareStr[0]);//页面中传过来的计算结果
			ctx.set("result", result);
			ctx.set("paramResult", paramResult);
			//对比两个值是否相等
			if ("true".equalsIgnoreCase(String.valueOf(fel.eval("result==paramResult")))) {
				return true;
			} else {
				log.info(param.get("formulaName") + "[" + param.get("rulesNo") + "][" + formulaCal + "]-公式校验失败！");
				throw new BusinessException(param.get("rulesNo") + "|" + param.get("formulaName") + ",数据验证失败！");
			}

		}
		Object result = fel.eval(formulaCal);
		log.info("numValidate-规则[" + param.get("formulaName") + "][" + formulaCal + "]->处理结果：" + result);
		if (!"true".equalsIgnoreCase(String.valueOf(result))) {
			log.info(param.get("formulaName") + "[" + param.get("rulesNo") + "][" + formulaCal + "]-公式校验失败！");
			throw new BusinessException(param.get("rulesNo") + "|" + param.get("formulaName") + ",数据验证失败！|"
					+ param.get("paramNo"));
		}
		return true;
	}

	private boolean dateValidate(String formulaCal, Map<String, Object> param) {
		FelEngine fel = new FelEngineImpl();
		String expPrefix = formulaCal;
		String keys[] = formulaCal.split(":");
		String enumKey = "dateCompare";
		if (keys.length > 1) {
			enumKey = keys[0];
			expPrefix = keys[1];
		}
		for (String key : param.keySet()) {
			if (expPrefix.indexOf(key) != -1) {
				expPrefix = expPrefix.replace(key, String.valueOf(param.get(key)));
			}
		}
		String exp = "";
		if (expPrefix.indexOf("certEndTime") != -1) {
			fel.addFun(FelFunction.getInstance().dateValidate());
			exp = "dateValidate('dateCompare','" + expPrefix + "')";
		}
		Object eval = fel.eval(exp);
		if (Validator.isNull(String.valueOf(eval))) {
			log.info(param.get("formulaName") + "[" + param.get("rulesNo") + "][" + formulaCal + "]-公式校验失败！");
			throw new BusinessException(param.get("rulesNo") + "|" + param.get("formulaName") + ",数据验证失败！");
		}
		eval = fel.eval(String.valueOf(eval));
		log.info("规则[" + param.get("formulaName") + "][" + eval + "]->处理结果：" + eval);
		if (!"true".equalsIgnoreCase(String.valueOf(eval))) {
			log.info(param.get("formulaName") + "[" + param.get("rulesNo") + "][" + formulaCal + "]-公式校验失败！");
			throw new BusinessException(param.get("rulesNo") + "|" + param.get("formulaName") + ",数据验证失败！");
		}
		return true;
	}

	/**
	 * description:  日期 公式计算类
	 */
	private Object dateCalculate(String formulaCal, Map<String, Object> param) {
		FelEngine fel = new FelEngineImpl();
		String str[] = formulaCal.split("=");
		String expPrefix = str[1];
		//如果含有sysdate，则将sysdate替换为当前时间。
		String keys[] = str[0].split(":");
		String enumKey = "sumDate";
		if (keys.length > 1) {
			enumKey = keys[0];
		}
		if (expPrefix.indexOf("sysdate") != -1) {
			expPrefix = expPrefix.replace("sysdate", DateUtils.getToday());
		}
		if (expPrefix.indexOf("systime") != -1) {
			expPrefix = expPrefix.replace("systime", DateUtils.Now.fmt_HHmmss());
		}
		if (expPrefix.indexOf("sysDateTime") != -1) {
			expPrefix = expPrefix.replace("sysDateTime", DateUtils.Now.fmt_yyyyMMdd_HHmmss());

		}
		//		if (formulaCal.indexOf("sysLongdate") > 0) {
		//			return System.currentTimeMillis() + "";
		//		}
		//trs.orderDate = sysdate
		for (String key : param.keySet()) {
			if (expPrefix.indexOf(key) != -1) {
				expPrefix = expPrefix.replace(key, String.valueOf(param.get(key)));
			}
		}
		String exp = "";
		fel.addFun(FelFunction.getInstance().dateCalculate());
		//		String args[] = new String[2];
		//		args[0]=enumKey;

		exp = "dateCalculate('" + enumKey + "','" + expPrefix + "')";
		Object eval = fel.eval(exp);
		log.info("规则[" + param.get("formulaName") + "][" + exp + "]->处理结果：" + eval);
		return eval;
	}

	private String densgerSql(ParamsVo vo, String prefix) {
		String sortCode = "";
		String tab = upperCharToUnderLine(prefix);
		if (tab.indexOf("_") == -1)
			return "";
		sortCode = tab.substring(tab.indexOf("_") + 1);
		String key = sortCode + "_tableAttr";
		String content = String.valueOf(SystemTools.getInstance().getCache("").getCacheObjectByKey(key));
		if (Validator.isNotNull(content))
			return content;
		return "1;*;info_id;" + tab;
	}

	/**
	 * description:  将类属性改成数据字段名
	 */
	private String upperCharToUnderLine(String param) {
		Pattern p = Pattern.compile("[A-Z]");
		if (param == null || param.equals("")) {
			return "";
		}
		StringBuilder builder = new StringBuilder(param);
		Matcher mc = p.matcher(param);
		int i = 0;
		while (mc.find()) {
			builder.replace(mc.start() + i, mc.end() + i, "_" + mc.group().toLowerCase());
			i++;
		}
		if ('_' == builder.charAt(0)) {
			builder.deleteCharAt(0);
		}
		return builder.toString();
	}

	private boolean isNumeric(String str) {
		Pattern pattern = Pattern.compile("(^[0-9]+(.[0-9]{1,6})?$)|(^\\-[0-9]+(.[0-9]{1,6})?$)");
		return pattern.matcher(str).matches();
	}

	private boolean isDate(String str) {
		Pattern pattern = Pattern
				.compile("(\\d{4}-\\d{1,2}-\\d{1,2})|(\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{2}:\\d{2}:\\d{2})");
		return pattern.matcher(str).matches();
	}

	public static void main(String[] args) {
		FelEngine fel = new FelEngineImpl();
		FelContext ctx = fel.getContext();
		ctx.set("totalMoney", 1000);
		ctx.set("buyFee", 10);
		ctx.set("sellFee", 20);
		ctx.set("trsOrder_orderFlag", "sell");
		String eval = "(trsOrder_orderFlag==[buy])?(totalMoney+buyFee):(sellFee)";

		Object result = fel.eval(eval);
		System.out.println(result);
	}

}
